# gcc -da language lexer+parser to use with packcc parser generator

# start of function in gcc da output is
# ;; Function f1 (f1, funcdef_no=6, decl_uid=2856, cgraph_uid=7, symbol_order=6)

# start of a basic block in gcc da output
# ;; basic block 2, loop depth 0, maybe hot

# block linkage in gcc da output
# block 0 is entry, block 1 is exit
# ;;  prev block 0, next block 1, flags: (NEW, REACHABLE, RTL)
# ;;  prev block 5, next block 1, flags: (NEW, REACHABLE, RTL)

# block linkage in gcc da output
# ;;  pred:       4
# ;;              5 (FALLTHRU)
# or
# ;;  pred:       4
# followed by (

# also
# ;;   basic block 5, loop depth 0
# ;;    pred:       3
# ;;                4
#   # _1 = PHI <_11(3), _10(4)>
# <L2>:
#   return _1;
# ;;    succ:       EXIT

# also
# ;;  succ:       EXIT [always]  (FALLTHRU)

%prefix "gccda"

%source{

#include <stdio.h>

static int nlines = 1;

static char * funcname = "";
static char * funcuid = "";
static char *bbnum = "";
static char *bbprevnum = "";
static char *bbnextnum = "";
static char *bbprefflags = "";
static char *bbpred = "";

static int debug = 0;

static const char *dbg_str[] = { "Evaluating rule", "Matched rule", "Abandoning rule" };

#define PCC_DEBUG(event, rule, level, pos, buffer, length) \
    if (debug) { fprintf(stdout, "%*s%s %s @%d [%.*s]\n", (int)(level * 2), "", dbg_str[event], rule, (int)pos, (int)length,  buffer); fflush(stdout); }

    /* NOTE: To guarantee the output order, stderr, which can lead a race condition with stdout, is not used. */

static void pstartfunc (void)
{
  if (funcname) {
   if(strlen(funcname)) {
     /* set end/start with fixed bb numbers 0 and 1 */
     printf (" \"%s_%s_bb0\"[label=\"%s()\\nENTRY\"];\n", funcname,funcuid,funcname);
     printf (" \"%s_%s_bb1\"[label=\"%s()\\nEXIT\"];\n", funcname,funcuid,funcname);
   }
  }
  return;
}

static void pbbnum (void)
{
  printf (" \"%s_%s_bb%s\"[label=\"Block %s\"];\n", funcname,funcuid,bbnum,bbnum);
  return;
}

static void pbbprev (void)
{
  if (0) { printf (" \"%s_%s_bb%s\" -> \"%s_%s_bb%s\"[label=\"%s\"];\n", funcname,funcuid,bbprevnum,funcname,funcuid,bbnum,bbprefflags); }
  if (0) { printf (" \"%s_%s_bb%s\" -> \"%s_%s_bb%s\"[label=\"%s\"];\n", funcname,funcuid,bbnum,funcname,funcuid,bbnextnum,bbprefflags); }
  return;
}

static void pbbend (void)
{

 printf (" \"%s_%s_bb%s\" -> \"%s_%s_bb1\";\n", funcname,funcuid,bbnum,funcname,funcuid);

 return;
}

static void pbbpred (void)
{
  char *s = "";

  if(strcmp (bbpred,"ENTRY")==0) {
   s = "0";
  }else {
   s = bbpred;
  }

  printf (" \"%s_%s_bb%s\" -> \"%s_%s_bb%s\";\n", funcname,funcuid,s,funcname,funcuid,bbnum);

  return;
}

}

# start of input
file <- _ lines* _ !.

lines	<- line

line	<- func
	/  bbstart
	/ bbsuccend
	/ bbsucc
	/ bbprev
	/ bbpred
	/ (!endofline .)* endofline

bbsuccend	<- ';;  succ:       EXIT' (!endofline .)* { pbbend (); }

bbsucc	<- succlines

succlines	<- succline

succline	<- ';;  succ:       ' succline2

succline2	<- succnum
	/ ';;' (' ')* succnum

succnum	<- (!(endofline).)*

bbpred	<- predlines

predlines	<- predline+

predline	<- ';;  pred:       ' prednum predline2*

predline2 <- ';;' ' '* prednum

prednum	<- prednum2 prenum3 endofline

prednum2	<- (!(endofline/'('/' ').)* { bbpred = strdup ($0); if (0) printf("// \"%s\" prednum line %d\n",$0,nlines); pbbpred(); }

prenum3	<- (!(endofline).)*

bbprev	<- ';;  prev block ' prevnum ', next block ' nextnum ', flags: ' prefflags { pbbprev(); }

prefflags	<- (!endofline .)* { bbprefflags = strdup ($0); }

nextnum	<- (!',' .)* { bbnextnum = strdup ($0); }

prevnum	<- (!',' .)* { bbprevnum = strdup ($0); }

bbstart	<- ';; basic block ' bbnum bbrest

bbnum	<- (!',' .)* { bbnum = strdup ($0); if (0) printf("// %s\n",$0); pbbnum(); }

bbrest	<- (!endofline .)*

func	<- ';; Function ' funcname ' ' funcuid funcrest { pstartfunc(); }

funcname	<- (!' ' .)* { if (0) printf("// %s\n",$0); funcname = strdup($0); }

funcuid	<- (!'decl_uid=' .)* 'decl_uid=' fuid

fuid	<- (!',' .)* { if (0) printf("// %s\n",$0); funcuid = strdup($0); }

funcrest	<- (!endofline .)* 


_	<-		(space)*

space	<-	(' ' / '\t' / endofline)

endofline	<-	( '\r\n' / '\n' / '\r' / '\n\r' ) { nlines++; }

%%

int main() {
    gccda_context_t *ctx = gccda_create(NULL);
    printf ("digraph g {\n");
    while (gccda_parse(ctx, NULL)){;}
    gccda_destroy(ctx);
    printf("}\n/* parsed %d lines */\n",nlines);
    return 0;
}
